/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"
#include "test_helper.h"
#include "include/coretypes/tagged_value.h"
#include "include/runtime.h"
#include "include/runtime_options.h"
#include "plugins/ecmascript/runtime/js_handle.h"
#include "plugins/ecmascript/runtime/object_factory.h"
#include "plugins/ecmascript/runtime/ecma_vm.h"
#include "plugins/ecmascript/runtime/global_env.h"

// NOLINTNEXTLINE(google-build-using-namespace)
using namespace ark::ecmascript;

namespace ark::test {
class SepareteJSVMTest : public testing::Test {
public:
    static void SetUpTestCase()
    {
        RuntimeOptions options;
        options.SetBootClassSpaces({"core", "ecmascript"});
        options.SetBootIntrinsicSpaces({"ecmascript"});
        options.SetRuntimeType("core");
        options.SetBootPandaFiles({});
        options.SetShouldLoadBootPandaFiles(false);
        options.SetRunGcInPlace(true);
        options.SetGcType("g1-gc");
        [[maybe_unused]] bool success = Runtime::Create(options);
        ASSERT_TRUE(success) << "Cannot create Runtime";
    }

    static void TearDownTestCase()
    {
        [[maybe_unused]] bool success = Runtime::Destroy();
        ASSERT_TRUE(success) << "Cannot destroy Runtime";
    }

    EcmaVM *CreateJSVM()
    {
        JSRuntimeOptions options;
        options.SetBootPandaFiles({});
        options.SetLoadRuntimes({"ecmascript"});
        options.SetRunGcInPlace(true);
        options.SetGcType("g1-gc");
        EcmaVM *ecmaVm = EcmaVM::Create(options);
        ecmaVm->StartGC();
        return ecmaVm;
    }
};

TEST_F(SepareteJSVMTest, CreateInstance)
{
    std::function<void()> func([this]() {
        auto ecmaVm = SepareteJSVMTest::CreateJSVM();
        ASSERT_TRUE(ecmaVm != nullptr);
        {
            auto *thread = ecmaVm->GetAssociatedJSThread();
            ScopedManagedCodeThread s(thread);
            [[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);

            JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
            JSHandle<JSTaggedValue> dynclass = globalEnv->GetObjectFunction();
            JSHandle<JSObject> jsobject =
                thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(dynclass), dynclass);
            JSHandle<JSObject> jsobject2 =
                thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(dynclass), dynclass);
            EXPECT_TRUE(*jsobject != nullptr);
            EXPECT_TRUE(*jsobject2 != nullptr);
            EXPECT_TRUE(!jsobject->IsCallable());
        }

        EcmaVM::Destroy(ecmaVm);
    });

    std::thread vmT1(func);

    vmT1.join();
}

}  // namespace ark::test
